function LeapDevice() {}

LeapDevice.DESK = 0
LeapDevice.HDM = 1

LeapDevice.initialise = () => {
  LeapDevice.scene = new THREE.Scene()

  LeapDevice.boneMeshes = []
  LeapDevice.armMeshes = []

  LeapDevice.physicsWorld = null
  LeapDevice.physicsBodys = []

  LeapDevice.useArm = false
  LeapDevice.mode = LeapDevice.DESK
  LeapDevice.scale = new THREE.Vector3(1, 1, 1)

  LeapDevice.controller = new Leap.Controller()
  Leap.loop({ background: true }, LeapDevice.updateLeap).connect()
}

LeapDevice.setMode = (mode) => {
  LeapDevice.mode = mode
}

LeapDevice.gestureOccuring = (gesture) => {
  // TODO: this
  return false
}

LeapDevice.updateLeap = (frame) => {
  LeapDevice.armMeshes.forEach((item) => {
    LeapDevice.scene.remove(item)
  })

  LeapDevice.boneMeshes.forEach((item) => {
    LeapDevice.scene.remove(item)
  })

  var countBones = 0
  var countArms = 0

  for (var hand of frame.hands) {
    var material = new THREE.MeshPhongMaterial({ color: 0x00ff00 })

    for (var finger of hand.fingers) {
      for (var bone of finger.bones) {
        if (countBones++ === 0) {
          continue
        }

        var boneMesh = LeapDevice.boneMeshes[countBones]
                        || LeapDevice.addMesh(LeapDevice.boneMeshes, material)
        LeapDevice.updateMesh(bone, boneMesh)
      }
    }

    var arm = hand.arm

    if (LeapDevice.showArm) {
      var armMesh = LeapDevice.armMeshes[countArms++]
                      || LeapDevice.addMesh(LeapDevice.armMeshes)
      LeapDevice.updateMesh(arm, armMesh)
      armMesh.scale.set(arm.width/1200, arm.width/300, arm.length/150)
    }
  }

  if (LeapDevice.physicsWorld !== null) {
    LeapDevice.updatePhysics(LeapDevice.scene, LeapDevice.physicsWorld)
  }
}

LeapDevice.updatePhysics = (object, world) => {
  LeapDevice.physicsBodys.forEach((item) => {
    LeapDevice.physicsWorld.removeBody(item)
  })
  LeapDevice.physicsBodys = []

  for(var j = 0; j < object.children.length; j++) {
    var box = new THREE.BoundingBoxHelper(object.children[j])
    box.update()

    var hs = new THREE.Vector3(box.box.max.x - box.box.min.x, box.box.max.y - box.box.min.y, box.box.max.z - box.box.min.z)
    hs.x *= object.scale.x
    hs.y *= object.scale.y
    hs.z *= object.scale.z
    hs.divideScalar(2)

    var pos = box.box.center()
    pos.x *= object.scale.x
    pos.y *= object.scale.y
    pos.z *= object.scale.z
    pos.add(object.position)

    var shape = new CANNON.Box(new CANNON.Vec3(hs.x, hs.y, hs.z))
    var body = new CANNON.Body({mass:0})
    body.addShape(shape)
    body.position.set(pos.x - object.position.x, pos.y - object.position.y, pos.z - object.position.z)
    body.updateMassProperties()

    LeapDevice.physics_bodys.push(body);
    world.addBody(body);
  }
}

LeapDevice.addMesh = (meshes, material) => {
  var geometry = new THREE.BoxGeometry(1, 1, 1)
  var mesh = new THREE.Mesh(geometry, material)
  meshes.push(mesh)
  return mesh
}

LeapDevice.updateMesh = (bone, mesh) => {
  mesh.position.fromArray(bone.center())
  mesh.position.divideScalar(150)

  mesh.setRotationFromMatrix((new THREE.Matrix4()).fromArray(bone.matrix()))
  mesh.scale.set(bone.width/150, bone.width/150, bone.length/150)

  LeapDevice.scene.add(mesh)
}
